更新失敗怎麼辦?! Σ(゚д゚lll)
更新上版難免會遇到更新失敗,或程式碼出狀況需要立即退版的情形,
沒錯!作為容器管理領域的領導者,Kubernetes 自然也具備完善的例外處理機制。
Deployment 除了更新策略,也包含並自動執行滾動更新和回滾操作,如果更新版本時失敗,可以自動回滾到先前的穩定版本,以此確保服務的高可用性。
在預設情況下,Deployment 部署的歷史記錄都保留在系統中,可以隨時 Rollback。
先確認目前的部署版本
kubectl rollout history deployment <deployment-name>
# 也可以使用
kubectl rollout history deployment/<deployment-name>
目前最新版是 revision 3,如果要 rollback 到 revision 2 可以執行到上一版的指令:
kubectl rollout undo deployment nginx-deployment
執行完成後再次執行 rollout history
可以發現 revision 多了新的一版:revision 4,但是revision 2 卻不見了。
這和 Kubernetes 的機制有關:
當 Deployment 從 revision 3 rollback 回 revision 2 時,Kubernetes 不是直接將元件調整回 reversion 2,而是建立了一個新的 revision (revision 4),這是為了避免混淆和衝突。
kubectl rollout
這個指令做的是 執行 rollback 和 建立新版本,其本身不會直接刪除舊版本。
但是 Kubernetes 會 (⁎⁍̴̛ᴗ⁍̴̛⁎)
為了優化儲存和管理,Deployment 在建立新的 revision 時,會刪除與現版本完全相同
的舊版本。
為什麼有些 CHANGE-CAUSE 有指令,有些卻是 <none>?
差別在於更新用的指令!
# 這個會留下紀錄
kubectl apply -f nginx-deployment.yaml --record
# 這個不會
kubectl apply -f nginx-deployment.yaml
--record
指令可以用於更新時紀錄更新異動指令,不過當你真的下了這個指令就會發現...
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deployment configured
--record
指令要被棄用啦!!!
畢竟 record 只能記下指令,要是每次都是更新 yaml 檔案,也只會出現一堆 kubectl apply -f nginx-deployment.yaml --record,根本也分不清楚誰是誰。
那要怎麼寫更新紀錄?
可以使用 kubernetes.io/change-cause
註解!
使用方式有兩種:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kubernetes.io/change-cause: "Deployed with nginx:1.11.5"
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx-app
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: nginx
image: nginx:1.11.5
ports:
- containerPort: 80
在 metadata
中加上 annotations
,kubernetes.io/change-cause:<自行撰寫的更新訊息>,就可以將自訂的更新內容記錄在 history revision 中囉!
執行結果:
再啟一個 Deployment2 (因為前一版已經被我試得亂七八糟了)
先不寫 annotations,直接執行 apply
然後修改 nginx 版本為 1.17
,再次執行 apply
指令,完成後確認目前版本。
然後執行 annotate
指令:
kubectl annotate deployment <deployment-name> kubernetes.io/change-cause="更新說明"
# 範例
kubectl annotate deployment nginx-dp kubernetes.io/change-cause="Updated image to nginx:1.17"
這樣就可以將註解加上去了... 嗎?
不見得喔(´・ω・`)annotate
指令雖然可以把忘記寫的註記加上去,卻只是針對 Deployment 元件做異動。
分別確認建立用的 yaml 檔和 Kubernetes 中的 Deployment,yaml 檔並沒有加上註記。
所以,如果往後繼續使用這個檔案做 apply
,一樣不會留有異動紀錄。
另外,如果在這個情況直接用指令更新 Deployment...
就會再次出現已經寫在 Deployment 中的紀錄。
雖然是可以再下一次 annotate
調整內容,但這樣下去沒完沒了啊!!!
只看 yaml file 也根本不會發現註記錯誤的問題。
所以還是比較推薦使用 yaml file 維護的時候就好好寫在檔案裡,沒事不要手動下指令改元件,避免一時不注意就變成維護上的困擾。
那可以
apply
的時候就直接寫好註解嗎?嗯... 不行。
apply
指令無法和annotate
同時執行。那是不是不要同時就可以了?
... 我最討厭像你這樣直覺敏銳的工程師了
硬要做的話串聯指令執行的確也可以達到一樣的效果。
kubectl apply -f deployment-2.yaml && kubectl annotate deployment nginx-dp kubernetes.io/change-cause="Deployed with nginx:1.17"
但要是哪一次忘記寫就又會繞回到前面 yaml 檔與實際元件不同步的問題,不推薦。
(但若是做成腳本運行又是另外一回事了)
本篇介紹了使用 kubectl rollout
、apply
、annotate
等指令進行 Deployment 管理時,關於記錄版本和 Rollback 歷史的問題,要有效管理 Deployment 版本記錄(特別是在未來 --record
被移除的情況下),最建議的還是回歸到 yaml file 的版本控制。畢竟 yaml file 只是文檔,可以用來管理的工具多不勝數,甚至可以根據使用的佈版流程挑選最合適的來使用。如果能將管理方式整併進 CI/CD 流程中做自動化,不管是版本管理上還是將來做問題排查,想必都可以省下不少心力吧。